home *** CD-ROM | disk | FTP | other *** search
- ;/* "C:Execute" me to compile me with SAS/C 6
- Set file Device-Handler
-
- sc:c/sc MOD NOICON VERBOSE STRMERGE UNSCHAR NOSTKCHK IGNORE=73 MOD CSRC $file.c
- sc:c/slink NOICONS FROM $file.o TO $file LIB lib:amiga.lib,lib:sc.lib,lib:debug.lib VERBOSE SMALLCODE SMALLDATA NODEBUG
- protect $file +p
-
- UnSet opt
- UnSet file
- Quit
- */
-
- /*F*/ /* autodoc */
- #if 0
- AUTODOC Device-Handler
- **
- ** $VER: Device-Handler 1.4 (22 Feb 1995)
- **
- ** Original code was written by Matthias Scheler. The original
- ** distribution archive of Matthias has been included.
- **
- **
- ** NAME
- ** Device-Handler - UNIX-like raw device access
- **
- ** WARNING
- ** This software is intended for advanced users only. I *strongly*
- ** recommend all people who do not understand every detail given
- ** herein to obtain further information about ->AmigaDOS-Devices
- ** and ->Handlers and their implementation on top of ->Exec
- ** device drivers.
- **
- ** ** WRONG USAGE OF THIS SOFTWARE WILL MOST LIKELY RESULT IN **
- ** ** SEVERE LOSS OF DATA! **
- **
- ** As this software is freeware in cases of data disruption you
- ** will find _nobody_ being responsible except yourself. Especially
- ** Matthias and me reject any liability.
- **
- ** FUNCTION
- ** Amiga Users often put a jealous glance to the UNIX world, were
- ** raw device access is as simple as nowhere else. Several solutions
- ** to fix this for Amigas have been provided in the past. One of these,
- ** the DEV: handler by Matthias Scheler, has been taken to base this
- ** software on.
- **
- ** Specifically, the original DEV: has the considerable drawback that it
- ** only worked with devices that supported the ->TD_GETGEOMETRY
- ** ->IORequest. Unfortunatly a lot of harddisk- (and other) drivers don't
- ** implement this command.
- **
- ** So I decided to derive the Exec-device selection from on the AmigaDOS
- ** stream name in such way, that the user provides the Name of an
- ** AmigaDOS Handler instead of the Exec-Device. There are system conform
- ** ways to find out on top of which Exec-device an AmigaDOS handler is
- ** running, so why not leaving this job to the DEV:-Handler ?
- **
- ** With my DEV: enhancement, you may type things like "DEV:df0" or
- ** "DEV:dh0", you get the general idea. Further improvements include the
- ** ability to limit the total size which is allowed to read or write, and
- ** to specify the low- and high cylinders to be used.
- **
- ** Note that the physical definition is completely retrieved from the
- ** given handler name (e.g. dh0), so there are some implications:
- **
- ** * Exec-device will be always correct
- ** * Exec-device unit will be allways correspond to the unit
- ** the AmigaDOS handler works on, releasing you from dealing whith
- ** it and thus making the usage of DEV: _much_ safer!
- ** * Exec-device OpenDevice() flags are always correct
- ** * Exec-device buffer memory type is always correct
- ** * Most often you will want to use DEV: for ->UNIX tar and will want
- ** to start writing exactly at block 0. For most floppy-base devices
- ** this will be correct automatically. In contrast, nearly every
- ** harddisk contains a ->RigidDiskBlock and the actual partitions
- ** are located behind this, usually having a low-cylinder of about 3.
- ** To archieve the intended bahaviour, you should create a special
- ** DOSDriver/mountlist entry, such as:
- **
- ** RDH0: /* raw dh0 */
- ** Device = scsi.device /* change this accordingly */
- ** Unit = 1
- ** Flags = 0
- ** Surfaces = 5
- ** BlocksPerTrack = 17
- ** LowCyl = 0 ; /* specify here full range */
- ** HighCyl = 1023 /* of cylinders */
- ** Stacksize = 4000
- ** Priority = 5
- ** GlobVec = -1
- ** BufMemType = 0
- ** #
- **
- ** Another way is to use the LOCYL stream name option. Again note:
- ** Playing around with LOCYL or HICYL is a pretty dangerous thing.
- ** It is always advised to write a dedicated mountlist/DOSDriver.
- **
- ** Plead read also the original documentation of the DEV:-handler.
- **
- ** STREAM NAME
- **
- ** The stream name is constructed as following:
- **
- ** DEV:<DOSHANDLER>[/<MAXLEN>][/LOCYL=<NUM>][/HICYL=<NUM>]
- **
- ** During stream name processing, all slashes are removed, thus creating
- ** a standard AmigaDOS ReadArgs()-style text line, as you know it from
- ** all CLI-Programs (I suppose you deleted all those that don't use
- ** ReadArgs() ;).
- **
- ** Additionally, all dots ('.') which are not part of a quoted text, are
- ** substituted by an equation symbol ('='). That comes in handy when using
- ** the LOCYL or HICYL options. AmigaDOS strips all equations that are not
- ** quoted. Thus, the command "type dev:df0/locyl=3" would lead to an error,
- ** as the handler would get the text "dev:df0/locyl" instead of
- ** "dev:df0/locyl=3". So, either use the dot or quote the whole stream spec.
- **
- ** *Any* number which is to pass to the handler may start with '$' or '0x'
- ** or '0X' to indicate hexadecimal notation (default is decimal). A
- ** trailing 'M' tells the handler to interprete it as a mega-value,
- ** (i.e. multiply by 1024^2) and 'K' to signal a kilo value (factor 1024).
- ** All charactes are case-insensitive.
- **
- ** The complete convenience of ReadArgs() applies to stream name
- ** construction:
- **
- ** The template is "DOSHANDLER/A,MAXLEN,LOCYL/K,HICYL/K"
- **
- ** DOSNAME
- ** A valid, AmigaDOS-device name such as DH0, df0, ... The device has
- ** to be mounted, though.
- **
- ** MAXLEN
- ** optional: maximum length of bytes to read or write. The (final)
- ** lo/hicyl may enclose a smaller space: the smallest space is always
- ** used. This value _must_ appear anywhere behind DOSHANDLER.
- **
- ** LOCYL
- ** Starting cylinder read from/write to. If higher than the (final)
- ** high cylinder, low cylinder is casted to high cylinder.
- **
- ** HICYL
- ** Ending cylinder. If higher than physical, physical is used.
- **
- ** Some example stream names:
- **
- ** DEV:df0
- ** DEV:dh0/1024
- ** DEV:dh0/1k
- ** DEV:dh0/LOCYL=0
- ** DEV:dh1/HICYL=1k/LOCYL=0M/20M
- ** DEV:df0/$1000
- ** DEV:df0/0x2000/LOCYL.4
- ** "DEV:df0/0X200/LOCYL=4"
- **
- ** AUTHOR
- **
- ** Marius Gröger,
- ** Bärstadter Str. 4
- ** D-65307 Bad Schwalbach
- ** email: mag@sysgo.de
- **
- ** SOURCE
- **
- ** The source code of "Device-Handler" has been written with the GoldED
- ** text editor (© Dietmar Eilert). Text folds start with "/*F*/"
- ** and end with "/*E*/".
- **
- ** You may make any changes to the source for your own use.
- ** If you consider them useful for everybody, tell me so I can
- ** include them to the next public release.
- **
- ** The documentation has been extracted with makedoc (© Stefan Ruppert).
- **
- ** $HISTORY:
- **
- ** 22 Feb 1995 : 001.004 : some bug-fixing
- ** 18 Feb 1995 : 001.003 : made Write() working...
- ** 20 Dec 1994 : 001.002 : + one task/multiple FileHandles
- ** + source-code rework
- ** + better stream name scanning by ReadArgs()
- ** + new option MAXLENGTH
- ** + new options LOCYL, HICYL
- ** + highly improved read/write operation
- ** 18 Dec 1994 : 001.001 : changed stream name convention
- ** 08 Dec 1994 : 001.000 : took over from Matthias Scheler
- **
- ENDDOC
- **
- #endif
- /*E*/
-
- /*F*/ /* debug */
- extern void KPrintF(char *, ...);
- /*#define d(x) { KPrintF("%s:%ld: ", __FUNC__, __LINE__); KPrintF x; }*/
- #define d(x) ;
- /*E*/
-
- /*F*/ /* includes */
- #include <exec/memory.h>
- #include <exec/execbase.h>
- #include <devices/trackdisk.h>
- #include <dos/dosextens.h>
- #include <dos/filehandler.h>
- #include <dos/dos.h>
-
- #define __USE_SYSBASE
-
- #include <clib/exec_protos.h>
- #include <pragmas/exec_pragmas.h>
-
- #include <clib/dos_protos.h>
- #include <pragmas/dos_pragmas.h>
-
- #include <clib/utility_protos.h>
- #include <pragmas/utility_pragmas.h>
-
- #include <string.h>
-
- /* fix include files (anyawy I'm not yet using them:
- ** what about sending me a diff-file ?)
- */
-
- #ifndef ACTION_GET_DISK_FSSM
- #define ACTION_GET_DISK_FSSM 4201
- #endif
-
- #ifndef ACTION_FREE_DISK_FSSM
- #define ACTION_FREE_DISK_FSSM 4202
- #endif
-
- /*E*/
-
- /*F*/ /* declarations */
-
- typedef struct GlobalData {
- struct Library *gd_SysBase, *gd_DOSBase, *gd_UtilityBase;
- struct MsgPort *gd_Port;
- struct DosList *gd_DosList;
- struct Process *gd_We;
- } *GD;
-
- #define SysBase (gd->gd_SysBase)
- #define DOSBase (gd->gd_DOSBase)
- #define UtilityBase (gd->gd_UtilityBase)
-
- #define BCPL_MAXNAME 256
- struct PrivateStreamData
- {
- struct IOStdReq *psd_IO;
- UBYTE psd_DOSName[BCPL_MAXNAME];
- UBYTE psd_Device[32];
- ULONG psd_Unit;
- ULONG psd_Flags;
- ULONG psd_BufMemType;
- LONG psd_LoCyl, psd_HiCyl;
- LONG psd_SectorSize;
- LONG psd_Offset;
- LONG psd_MaxLength;
-
- LONG psd_Pos;
- LONG psd_Len;
- LONG psd_Left;
- UBYTE *psd_Buffer;
- UBYTE *psd_Ptr;
- BOOL psd_Write;
- };
-
- #define MIN __builtin_min
- #define MAX __builtin_min
-
- #define STREAMNAME_TEMPLATE "DOSNAME/A,MAXLENGTH,LOCYL/K,HICYL/K"
- enum { ARG_DOSNAME=0, ARG_MAXLENGTH, ARG_LOCYL, ARG_HICYL, ARG_COUNT };
-
- /*E*/
-
- /*F*/ /* entry */
- static ULONG main(void);
- static ULONG __saveds __asm entry(register __a0 UBYTE *line, register __d0 ULONG len)
- {
- return(main());
- }
-
- const static UBYTE version[]= "\0$VER: Device-Handler 1.4 "__AMIGADATE__;
-
- /*E*/
-
- /*F*/ static struct DosPacket *WaitDosPacket(GD gd, struct MsgPort *port)
-
- {
- WaitPort(port);
- return (struct DosPacket *)(GetMsg(port)->mn_Node.ln_Name);
- }
- /*E*/
- /*F*/ static void ReplyDosPacket(GD gd, struct MsgPort *port, struct DosPacket *Packet,LONG Res1,LONG Res2)
- {
- struct MsgPort *reply = Packet->dp_Port;
-
- Packet->dp_Port = port;
- Packet->dp_Link->mn_Node.ln_Name = (char *)Packet;
- Packet->dp_Res1 = Res1;
- Packet->dp_Res2 = Res2;
-
- PutMsg (reply, Packet->dp_Link);
- }
- /*E*/
-
- /*F*/ static BOOL openres(GD gd)
- {
- BOOL rc = FALSE;
-
- d(("entered\n"))
-
- DOSBase = NULL;
- UtilityBase = NULL;
- gd->gd_Port = NULL;
-
- if (SysBase->lib_Version >= 37)
- {
- if (DOSBase = OpenLibrary("dos.library", 37))
- {
- if (UtilityBase = OpenLibrary("utility.library", 37))
- {
- if (gd->gd_Port = CreateMsgPort())
- {
- rc = TRUE;
- }
- else d(("no handler port\n"))
- }
- else d(("no utility V37\n"))
- }
- else d(("no dos V37\n"))
- }
- else d(("no exec V37\n"))
-
- d(("left: %ld\n",rc))
-
- return rc;
- }
- /*E*/
- /*F*/ static void closeres(GD gd)
- {
- d(("freeing port\n"))
- if (gd->gd_Port) DeleteMsgPort(gd->gd_Port);
-
- d(("closing dos\n"))
- if (DOSBase) CloseLibrary(DOSBase);
-
- d(("closing utility\n"))
- if (UtilityBase) CloseLibrary(UtilityBase);
- }
- /*E*/
-
- /*F*/ BOOL getul(GD gd, UBYTE *s, LONG *number)
- {
-
- #define IsDigit(c) ((c) >= '0' && (c) <= '9'))
- #define IsXDigit(c) (((c) >= '0' && (c) <= '9') || ((c) >= 'A' && (c) <= 'F'))
-
- BOOL hex, rc = TRUE;
- ULONG num;
- UBYTE c;
- WORD len;
-
- if (len = strlen(s))
- {
- if (!Strnicmp(s, "0x", 2))
- {
- hex = TRUE;
- s += 2;
- }
- else if (!Strnicmp(s, "$", 2))
- {
- hex = TRUE;
- s++;
- }
- else hex = FALSE;
-
- for(num=0;*s;s++)
- {
- c = ToUpper(*s);
- if (hex)
- {
- if (c >= '0' && c <= '9') num = num * 16 + c - '0';
- else if (c >= 'A' && c <= 'F') num = num * 16 + c - '0';
- else break;
- }
- else
- {
- if (c >= '0' && c <= '9') num = num * 10 + c - '0';
- else break;
- }
- }
-
- if (*s)
- {
- if (c == 'K') num *= 1024;
- else if (c == 'M') num *= 1024*1024;
- else rc = FALSE;
- }
- }
- else rc = FALSE;
-
- if (rc) *number = num;
-
- return rc;
- }
- /*E*/
- /*F*/ static void stream2rdargs(UBYTE *buffer)
- {
- UBYTE *p;
- enum { s_norm, s_esc, s_quote } s;
-
- for (p = buffer, s = s_norm; *p; p++)
- switch(s)
- {
- case s_norm:
- if (*p == '.') *p = '=';
- if (*p == '/') *p = '\040';
- else if (*p == '"') s = s_quote;
- break;
- case s_esc:
- s = s_quote;
- break;
- case s_quote:
- if (*p == '*') s = s_esc;
- if (*p == '"') s = s_norm;
- break;
- }
- }
- /*E*/
- /*F*/ static BOOL streamspecs(GD gd, struct PrivateStreamData *psd, BPTR streamname, LONG *res)
- {
- UBYTE *temp, *bstr, *start;
- BOOL rc = FALSE;
- LONG rdparam[ARG_COUNT];
- struct RDArgs *inrda, *rda;
-
- bstr = (UBYTE *)BADDR(streamname);
-
- if (temp = AllocVec(bstr[0]+2, MEMF_ANY))
- {
- if (inrda = AllocDosObject(DOS_RDARGS, NULL))
- {
- strncpy(temp, bstr+1, bstr[0]);
- temp[bstr[0]] = '\n';
- temp[bstr[0]+1] = '\0';
-
- if (start = (UBYTE*)strchr((char*)temp, ':'))
- {
- stream2rdargs(++start);
-
- inrda->RDA_Source.CS_Buffer = start;
- inrda->RDA_Source.CS_Length = strlen(start);
- inrda->RDA_Source.CS_CurChr = 0;
-
- psd->psd_MaxLength = 0x7fffffff;
- psd->psd_LoCyl = 0;
- psd->psd_HiCyl = 0x7fffffff;
- memset(rdparam, 0, ARG_COUNT*sizeof(LONG));
- d(("readargs(%s)\n",start))
- if (rda = ReadArgs((UBYTE*)STREAMNAME_TEMPLATE, rdparam, inrda))
- {
- rc = TRUE;
-
- strcpy(psd->psd_DOSName, (UBYTE*)rdparam[ARG_DOSNAME]);
- if (rdparam[ARG_MAXLENGTH]) rc = getul(gd,(UBYTE*)rdparam[ARG_MAXLENGTH], &psd->psd_MaxLength);
- if (rc && rdparam[ARG_LOCYL]) rc = getul(gd,(UBYTE*)rdparam[ARG_LOCYL], &psd->psd_LoCyl);
- if (rc && rdparam[ARG_HICYL]) rc = getul(gd,(UBYTE*)rdparam[ARG_HICYL], &psd->psd_HiCyl);
-
- d(("after ReadArgs(): doshandler %s maxlen %lu locyl %lu hicyl %lu\n",
- psd->psd_DOSName,psd->psd_MaxLength,psd->psd_LoCyl,psd->psd_HiCyl))
-
- FreeArgs(rda);
- }
- else
- {
- d(("ReadArgs() failed\n"))
- *res = ERROR_BAD_STREAM_NAME;
- }
- }
- else
- {
- d(("no proper name\n"))
- *res = ERROR_BAD_STREAM_NAME;
- }
-
- FreeDosObject(DOS_RDARGS, inrda);
- }
- else
- {
- d(("no RDArgs\n"))
- *res = ERROR_NO_FREE_STORE;
- }
-
- FreeVec(temp);
- }
- else
- {
- d(("no more memory\n"))
- *res = ERROR_NO_FREE_STORE;
- }
-
- return rc;
- }
- /*E*/
-
- /*F*/ static BOOL FindDevice(GD gd, struct PrivateStreamData *psd)
- {
- struct DosList *dol;
- struct FileSysStartupMsg *fssm=NULL;
- BOOL rc = FALSE;
- UBYTE *name;
- UBYTE n;
- UBYTE pat[40];
-
- d(("entered: %s\n", psd->psd_DOSName))
-
- n = strlen(psd->psd_DOSName);
-
- if (dol = LockDosList(LDF_READ | LDF_DEVICES))
- {
- while(dol = NextDosEntry(dol, LDF_DEVICES))
- {
- name = (UBYTE*)BADDR(dol->dol_Name);
-
- memset(pat,0,40);
- strncpy(pat,name+1,name[0]);
- d(("%s\n",pat))
-
- if ((n == name[0]) && !Strnicmp((char*)(name+1), psd->psd_DOSName, n))
- {
- d(("found\n"))
-
- fssm = (struct FileSysStartupMsg*)BADDR(dol->dol_misc.dol_handler.dol_Startup);
-
- if (fssm)
- {
- struct DosEnvec *de = (struct DosEnvec *)BADDR(fssm->fssm_Environ);
-
- d(("found fssm\n"))
- /* note: fssm->fssm_Device is a NUL terminated BSTR!! :-) */
- strcpy((char*)psd->psd_Device, (char*)BADDR(fssm->fssm_Device)+1);
- psd->psd_Flags = fssm->fssm_Flags;
- psd->psd_Unit = fssm->fssm_Unit;
- psd->psd_BufMemType = de->de_BufMemType;
- psd->psd_SectorSize = 4 * de->de_SizeBlock;
- psd->psd_HiCyl = MIN(psd->psd_HiCyl, de->de_HighCyl);
- psd->psd_LoCyl = MIN(psd->psd_LoCyl, psd->psd_HiCyl);
- d(("de->de_BlocksPerTrack %ld, psd->psd_LoCyl %ld, de->de_Surfaces %ld, psd->psd_SectorSize %ld\n",
- de->de_BlocksPerTrack,psd->psd_LoCyl,de->de_Surfaces,psd->psd_SectorSize))
- psd->psd_Offset = de->de_BlocksPerTrack * psd->psd_LoCyl * de->de_Surfaces * psd->psd_SectorSize;
-
- psd->psd_Len = de->de_BlocksPerTrack * psd->psd_SectorSize * (psd->psd_HiCyl - psd->psd_LoCyl + 1) * de->de_Surfaces;
- psd->psd_Len = MIN(psd->psd_MaxLength, psd->psd_Len);
- d(("len %lu\n",psd->psd_Len))
-
- d(("device %s, unit %ld, flags %ld, secsiz %ld, off %ld\n",
- psd->psd_Device,psd->psd_Unit,psd->psd_Flags,psd->psd_SectorSize,psd->psd_Offset))
-
- rc = TRUE;
- }
- else
- d(("no fssm\n"))
-
- break;
- }
- }
-
- UnLockDosList(LDF_READ | LDF_DEVICES);
- }
-
- return(rc);
- }
- /*E*/
-
- /*F*/ static void __regargs OpenDH(GD gd, struct DosPacket *Pkt,ULONG *OpenCnt)
- {
- struct FileHandle *FH;
- struct PrivateStreamData *psd;
- struct MsgPort *IOPort;
- BOOL ok = FALSE;
-
- Pkt->dp_Res1 = DOSFALSE;
- FH = (struct FileHandle *)BADDR(Pkt->dp_Arg1);
- FH->fh_Port = (struct MsgPort *)FALSE;
- FH->fh_Arg1 = 0L;
-
- d(("allocing psd\n"))
- if (psd = AllocVec(sizeof(*psd),MEMF_PUBLIC|MEMF_CLEAR))
- {
- if (streamspecs(gd, psd, (BPTR)Pkt->dp_Arg3, &Pkt->dp_Res2))
- {
- d(("creating msgport\n"))
- if (IOPort=CreateMsgPort())
- {
- if (psd->psd_IO=CreateIORequest(IOPort, sizeof(struct IOStdReq)))
- {
- if (FindDevice(gd, psd))
- {
- if (OpenDevice(psd->psd_Device, psd->psd_Unit, (struct IORequest *)psd->psd_IO, psd->psd_Flags)==0L)
- {
- if (psd->psd_Buffer = AllocVec(psd->psd_SectorSize, psd->psd_BufMemType))
- {
- if (Pkt->dp_Type == ACTION_FINDOUTPUT)
- {
- psd->psd_Write = TRUE;
- psd->psd_IO->io_Command = CMD_WRITE;
- }
- else
- {
- psd->psd_Write = FALSE;
- psd->psd_IO->io_Command = CMD_READ;
- }
- psd->psd_Ptr = psd->psd_Buffer;
- psd->psd_Pos = 0;
- psd->psd_Left = 0;
-
- FH->fh_Arg1 = (LONG)psd;
-
- Pkt->dp_Res1 = DOSTRUE;
- Pkt->dp_Res2 = 0L;
-
- (*OpenCnt)++;
- ok = TRUE;
- }
- else Pkt->dp_Res2 = ERROR_NO_FREE_STORE;
-
- if (!ok) CloseDevice ((struct IORequest *)psd->psd_IO);
- }
- else
- {
- d(("could not open device >%s<\n",psd->psd_Device))
- Pkt->dp_Res2 = ERROR_OBJECT_NOT_FOUND;
- }
- }
- else
- {
- d(("no device\n"))
- Pkt->dp_Res2 = ERROR_OBJECT_NOT_FOUND;
- }
-
- if (!ok) DeleteIORequest(psd->psd_IO);
- }
- else
- {
- d(("no iorequest\n"))
- Pkt->dp_Res2 = ERROR_NO_FREE_STORE;
- }
-
- if (!ok) DeleteMsgPort (IOPort);
- }
- else
- {
- d(("no msgport\n"))
- Pkt->dp_Res2 = ERROR_NO_FREE_STORE;
- }
- }
- else
- {
- d(("no streamspecs()\n"))
- }
- if (!ok) FreeVec (psd);
- }
- else
- {
- d(("no psd\n"))
- Pkt->dp_Res2 = ERROR_NO_FREE_STORE;
- }
-
- d(("leaving OpenDH() with Res2 = %ld\n",Pkt->dp_Res2))
- }
- /*E*/
- /*F*/ static void __regargs CloseDH(GD gd, struct PrivateStreamData *psd,ULONG *OpenCnt)
- {
- d(("CloseDH()\n"))
- if (psd->psd_Write)
- {
- if (psd->psd_Left < psd->psd_SectorSize)
- {
- d(("DoIO(CMD_WRITE)\n"))
-
- memset(psd->psd_Ptr,'\0',psd->psd_Left);
- psd->psd_IO->io_Length = psd->psd_SectorSize;
- psd->psd_IO->io_Data = psd->psd_Buffer;
- psd->psd_IO->io_Offset = psd->psd_Pos + psd->psd_Left-psd->psd_SectorSize;
- DoIO((struct IORequest *)psd->psd_IO);
- }
- psd->psd_IO->io_Command=CMD_UPDATE;
-
- d(("DoIO(CMD_UPDATE)\n"))
- DoIO((struct IORequest *)psd->psd_IO);
- }
-
- d(("FreeVec() buffer\n"))
-
- FreeVec(psd->psd_Buffer);
-
- d(("stopping motor off\n"))
- psd->psd_IO->io_Command = TD_MOTOR;
- psd->psd_IO->io_Length = 0L;
- DoIO((struct IORequest *)psd->psd_IO);
- d(("closing device\n"))
- CloseDevice ((struct IORequest *)psd->psd_IO);
-
- d(("deleting msg port\n"))
- DeleteMsgPort (psd->psd_IO->io_Message.mn_ReplyPort);
-
- d(("deleting stdio\n"))
- DeleteIORequest (psd->psd_IO);
-
- d(("FreeVec() rh\n"))
- FreeVec (psd);
-
- (*OpenCnt)--;
-
- d(("leaving closedh()\n"))
-
- }
- /*E*/
-
- /*F*/ static LONG __regargs RawRead(GD gd, struct PrivateStreamData *psd, UBYTE *Buffer, LONG Bytes, LONG *res2)
- {
- LONG LatchBytes, RDBytes;
- BOOL error = FALSE;
-
- LatchBytes = Bytes;
-
- /* check bouunds */
- if ((psd->psd_Pos + Bytes) > psd->psd_Len) Bytes = psd->psd_Len - psd->psd_Pos;
-
- d(("read %ld bytes\n",Bytes))
-
- /*
- ** first, read what's left in buffer
- */
- if (psd->psd_Left)
- {
- RDBytes=MIN(psd->psd_Left, Bytes);
- CopyMem(psd->psd_Ptr, Buffer, RDBytes);
-
- Buffer += RDBytes;
- Bytes -= RDBytes;
-
- psd->psd_Pos += RDBytes; /* incr. position in file */
- psd->psd_Ptr += RDBytes;
- psd->psd_Left -= RDBytes;
- }
-
- /*
- ** second, try to read as much blocks as possible directly to
- ** user buffer, avoiding CopyMem()
- */
- if (!error && (Bytes > psd->psd_SectorSize))
- {
- RDBytes = (Bytes / psd->psd_SectorSize) * psd->psd_SectorSize;
-
- psd->psd_IO->io_Data = Buffer;
- psd->psd_IO->io_Length = RDBytes;
- psd->psd_IO->io_Offset = psd->psd_Pos + psd->psd_Offset;
- if (DoIO((struct IORequest *)psd->psd_IO))
- {
- RDBytes = psd->psd_IO->io_Actual;
- error = TRUE;
- *res2 = psd->psd_IO->io_Error;
- }
- Buffer += RDBytes;
- Bytes -= RDBytes;
-
- psd->psd_Pos += RDBytes; /* incr. position in file */
- psd->psd_Left = 0; /* for safety, initialise buffer */
- psd->psd_Ptr = psd->psd_Buffer;
- }
-
- if (!error && Bytes)
- {
- /*
- ** now there are only some bytes < SectorSize left, so they fit into one buffer
- ** So, read a buffer and copy some bytes from it to user-buffer.
- */
- RDBytes = Bytes;
- psd->psd_IO->io_Length = psd->psd_SectorSize;
- psd->psd_IO->io_Data = psd->psd_Buffer;
- psd->psd_IO->io_Offset = psd->psd_Pos + psd->psd_Offset;
-
- if (DoIO((struct IORequest *)psd->psd_IO))
- {
- *res2 = psd->psd_IO->io_Error;
- RDBytes = psd->psd_IO->io_Actual;
- }
-
- CopyMem(psd->psd_Buffer, Buffer, RDBytes);
-
- psd->psd_Pos += RDBytes;
- psd->psd_Ptr = psd->psd_Buffer + RDBytes;
- psd->psd_Left = psd->psd_SectorSize - RDBytes;
-
- Bytes -= RDBytes;
- }
-
- return LatchBytes - Bytes;
- }
- /*E*/
- /*F*/ static LONG __regargs RawWrite(GD gd, struct PrivateStreamData *psd,UBYTE *Buffer,LONG Bytes, LONG *res2)
- {
- LONG LatchBytes,WRBytes;
- BOOL error = FALSE;
-
- LatchBytes = Bytes;
-
- /* check bouunds */
- if ((psd->psd_Pos + Bytes) > psd->psd_Len) Bytes = psd->psd_Len-psd->psd_Pos;
-
- d(("write %ld bytes\n",Bytes))
-
- /*
- ** first, take care for outstanding data
- */
- if (Bytes && psd->psd_Left)
- {
- WRBytes = MIN(psd->psd_Left, Bytes);
- CopyMem(Buffer, psd->psd_Ptr, WRBytes);
-
- psd->psd_Ptr += WRBytes; /* incr. position in buffer */
- psd->psd_Left -= WRBytes; /* decr. number of unused bytes */
-
- if (psd->psd_Left == 0) /* Buffer full ? */
- { /* then write it out */
- psd->psd_IO->io_Data = psd->psd_Buffer;
- psd->psd_IO->io_Length = psd->psd_SectorSize;
- psd->psd_IO->io_Offset = psd->psd_Pos + psd->psd_Offset;
- psd->psd_IO->io_Command = CMD_WRITE;
- if (DoIO((struct IORequest *)psd->psd_IO))
- {
- *res2 = psd->psd_IO->io_Error;
- WRBytes = psd->psd_IO->io_Actual;
- error = TRUE;
- }
-
- psd->psd_Ptr = psd->psd_Buffer; /* reset buffer pointers */
- psd->psd_Left = 0;
- }
-
- Buffer += WRBytes;
- Bytes -= WRBytes;
- psd->psd_Pos += WRBytes; /* incr. position in file */
- }
-
- if (!error && Bytes)
- {
- /*
- ** second, try to write as much blocks as possible directly from
- ** user buffer in one go, avoiding CopyMem() and multiple I/O-Requests
- */
- if (Bytes > psd->psd_SectorSize)
- {
- /* I don't like to use bit masking at this point */
- WRBytes = (Bytes / psd->psd_SectorSize) * psd->psd_SectorSize;
-
- psd->psd_IO->io_Data = Buffer;
- psd->psd_IO->io_Length = WRBytes;
- psd->psd_IO->io_Offset = psd->psd_Pos + psd->psd_Offset;
- psd->psd_IO->io_Command = CMD_WRITE;
- if (DoIO((struct IORequest *)psd->psd_IO))
- {
- *res2 = psd->psd_IO->io_Error;
- WRBytes = psd->psd_IO->io_Actual;
- error = TRUE;
- }
-
- Buffer += WRBytes;
- Bytes -= WRBytes;
- psd->psd_Pos += WRBytes; /* incr. position in file */
-
- psd->psd_Ptr = psd->psd_Buffer; /* for safety, reset buffer pointers */
- psd->psd_Left = 0;
- }
- }
-
- if (!error && Bytes)
- {
- /*
- ** now there are only some bytes < SectorSize left, and they fit into one
- ** buffer.
- ** NOTE: the actual writing is delayed to Close() or further Write()'s
- */
- WRBytes = Bytes;
- CopyMem(Buffer, psd->psd_Buffer, WRBytes);
-
- psd->psd_Pos += WRBytes; /* incr. position in file */
- Bytes -= WRBytes;
- Buffer += WRBytes;
-
- psd->psd_Ptr = psd->psd_Buffer + WRBytes; /* set position in buffer */
- psd->psd_Left = psd->psd_SectorSize - WRBytes; /* set number of unused bytes */
- }
-
- return LatchBytes - Bytes;
- }
- /*E*/
-
- /*F*/ static ULONG main(void)
- {
- struct GlobalData GlobalData;
- struct GlobalData *gd;
-
- struct DosPacket *Pkt;
- BOOL Done;
- ULONG OpenCnt;
-
- gd = &GlobalData;
-
- d(("Hello, this is the DEV-Handler\n"))
-
- SysBase = *(struct Library**)4L;
-
- if ((gd->gd_We = (struct Process *)FindTask(NULL))->pr_CLI) return RETURN_FAIL;
-
- d(("waiting for startup-packet...\n"))
- Pkt = WaitDosPacket(gd, &gd->gd_We->pr_MsgPort);
-
- if (openres(gd))
- {
- gd->gd_DosList = (struct DosList *)BADDR(Pkt->dp_Arg3);
- gd->gd_DosList->dol_Task = gd->gd_Port;
-
- d(("replying startup-packet...\n"))
- ReplyDosPacket(gd, gd->gd_Port, Pkt, DOSTRUE, Pkt->dp_Res2);
-
- Done=FALSE;
- OpenCnt=0L;
-
- d(("entering mainloop\n"))
-
- while (!Done)
- {
- Pkt=WaitDosPacket(gd, gd->gd_Port);
-
- d(("got packet %ld\n",Pkt->dp_Type))
-
- Pkt->dp_Res1 = DOSFALSE;
- Pkt->dp_Res2 = ERROR_ACTION_NOT_KNOWN;
-
- switch (Pkt->dp_Type)
- {
- case ACTION_FINDINPUT:
- case ACTION_FINDOUTPUT:
- OpenDH (gd, Pkt, &OpenCnt);
- ReplyDosPacket(gd, gd->gd_Port,Pkt, Pkt->dp_Res1, Pkt->dp_Res2);
- break;
-
- case ACTION_END:
- CloseDH (gd, (struct PrivateStreamData *)Pkt->dp_Arg1,&OpenCnt);
- ReplyDosPacket(gd, gd->gd_Port,Pkt, DOSTRUE, 0);
- break;
-
- case ACTION_READ:
- {
- struct PrivateStreamData *psd = (struct PrivateStreamData *)Pkt->dp_Arg1;
-
- if (psd && !psd->psd_Write)
- {
- LONG Bytes, error;
-
- Bytes = RawRead(gd, (struct PrivateStreamData *)Pkt->dp_Arg1,
- (UBYTE *)Pkt->dp_Arg2,Pkt->dp_Arg3, &error);
-
- ReplyDosPacket(gd, gd->gd_Port,Pkt, Bytes, error);
- }
- }
- break;
-
- case ACTION_WRITE:
- {
- struct PrivateStreamData *psd = (struct PrivateStreamData *)Pkt->dp_Arg1;
-
- if (psd && psd->psd_Write)
- {
- LONG Bytes, error;
-
- Bytes = RawWrite(gd, (struct PrivateStreamData *)Pkt->dp_Arg1,
- (UBYTE *)Pkt->dp_Arg2, Pkt->dp_Arg3, &error);
-
- ReplyDosPacket(gd, gd->gd_Port,Pkt, Bytes, error);
- }
- }
- break;
-
- case ACTION_IS_FILESYSTEM:
- ReplyDosPacket(gd, gd->gd_Port,Pkt, DOSFALSE, 0);
- break;
-
- case ACTION_SEEK:
- case ACTION_SET_FILE_SIZE:
- ReplyDosPacket(gd, gd->gd_Port,Pkt, -1,ERROR_ACTION_NOT_KNOWN);
- break;
-
- case ACTION_DIE:
- if (OpenCnt==0L)
- {
- d(("opencnt = 0\n"))
-
- if (IsListEmpty(&gd->gd_Port->mp_MsgList))
- {
- gd->gd_DosList->dol_Task = NULL;
-
- ReplyDosPacket(gd, gd->gd_Port,Pkt, DOSTRUE, 0);
-
- Done=TRUE;
- }
- else ReplyDosPacket(gd, gd->gd_Port,Pkt, DOSFALSE,ERROR_OBJECT_IN_USE);
- }
- else ReplyDosPacket(gd, gd->gd_Port,Pkt, DOSFALSE,ERROR_OBJECT_IN_USE);
- break;
-
- default:
- ReplyDosPacket(gd, gd->gd_Port, Pkt, DOSFALSE, ERROR_ACTION_NOT_KNOWN);
- break;
- }
- }
- }
- else ReplyDosPacket(gd, &gd->gd_We->pr_MsgPort, Pkt, DOSFALSE, ERROR_NO_FREE_STORE);
-
- closeres(gd);
-
- d(("returning\n"))
-
- return RETURN_OK;
- }
- /*E*/
-
-